﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using DailyPoetryX.Models;
using SQLite;

namespace DailyPoetryX.Services.Implementations {
    /// <summary>
    /// 诗词存储。
    /// </summary>
    public class PoetryStorage : IPoetryStorage {
        /******** 公开变量 ********/

        /// <summary>
        /// 诗词总数量。
        /// </summary>
        public const int NumberPoetry = 10273;

        /// <summary>
        /// 数据库名。
        /// </summary>
        public const string DbName = "poetrydb.sqlite3";

        /******** 私有变量 ********/

        /// <summary>
        /// 偏好存储。
        /// </summary>
        private IPreferenceStorage _preferenceStorage;

        /// <summary>
        /// 诗词数据库路径。
        /// </summary>
        private static readonly string PoetryDbPath =
            Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder
                    .LocalApplicationData), DbName);

        /// <summary>
        /// 数据库连接影子变量。
        /// </summary>
        private SQLiteAsyncConnection _connection;

        /// <summary>
        /// 数据库连接影子变量锁。
        /// </summary>
        private object _connectionLock = new object();

        /// <summary>
        /// 数据库连接。
        /// </summary>
        private SQLiteAsyncConnection Connection {
            get {
                if (_connection == null) {
                    lock (_connectionLock) {
                        if (_connection == null) {
                            _connection =
                                new SQLiteAsyncConnection(PoetryDbPath);
                        }
                    }
                }

                return _connection;
            }
        }

        /******** 继承方法 ********/

        /// <summary>
        /// 是否已经初始化。
        /// </summary>
        public bool Initialized() =>
            _preferenceStorage.Get(PoetryStorageConstants.VersionKey, -1) ==
            PoetryStorageConstants.Version;

        /// <summary>
        /// 初始化。
        /// </summary>
        public async Task InitializeAsync() {
            using (var dbFileStream =
                new FileStream(PoetryDbPath, FileMode.Create))
            using (var dbAssetStream = Assembly.GetExecutingAssembly()
                .GetManifestResourceStream(DbName)) {
                await dbAssetStream.CopyToAsync(dbFileStream);
            }

            _preferenceStorage.Set(PoetryStorageConstants.VersionKey,
                PoetryStorageConstants.Version);
        }

        /// <summary>
        /// 获取满足给定条件的诗词集合。
        /// </summary>
        /// <param name="where">Where条件。</param>
        /// <param name="skip">跳过数量。</param>
        /// <param name="take">获取数量。</param>
        public async Task<IList<Poetry>> GetPoetriesAsync(
            Expression<Func<Poetry, bool>> where, int skip, int take) =>
            await Connection.Table<Poetry>().Where(where).Skip(skip).Take(take)
                .ToListAsync();

        /// <summary>
        /// 获取一个诗词。
        /// </summary>
        /// <param name="id">诗词id。</param>
        public async Task<Poetry> GetPoetryAsync(int id) =>
            await Connection.Table<Poetry>()
                .FirstOrDefaultAsync(p => p.Id == id);

        /******** 公开方法 ********/

        /// <summary>
        /// 诗词存储。
        /// </summary>
        /// <param name="preferenceStorage">偏好存储。</param>
        public PoetryStorage(IPreferenceStorage preferenceStorage) {
            _preferenceStorage = preferenceStorage;
        }

        /// <summary>
        /// 关闭数据库。
        /// </summary>
        public async Task CloseAsync() => await Connection.CloseAsync();

        /******** 私有方法 ********/
    }
}